package com.cqemme.activitiservice.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.cqemme.activitiservice.feign.SchoolServiceFeign;
import com.cqemme.activitiservice.feign.WebsocketService;
import com.cqemme.activitiservice.po.AlarmMessageInfo;
import com.cqemme.activitiservice.po.CloseTaskPo;
import com.cqemme.activitiservice.po.CompleteTaskPo;
import com.cqemme.activitiservice.service.ActivitiUtilService;
import com.cqemme.activitiservice.service.AlarmService;
import com.cqemme.activitiservice.service.CommonService;
import com.cqemme.activitiservice.utils.EmptyChecker;
import com.cqemme.comm.enums.AlarmType;
import com.cqemme.comm.po.CurrentLoginUser;
import com.cqemme.comm.po.Result;
import com.cqemme.comm.utils.DateUtils;
import com.cqemme.comm.utils.JackSonUtils;
import com.cqemme.comm.utils.ResultCodeMsg;
import com.cqemme.comm.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author nejery
 */
@Service
@Slf4j
public class AlarmServiceImpl implements AlarmService {

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private CommonService commonService;

    @Resource
    private SchoolServiceFeign schoolServiceFeign;

    @Resource
    private HistoryService historyService;

    @Resource
    private TaskService taskService;

    @Resource
    private ActivitiUtilService activitiUtilService;

    @Resource
    private WebsocketService websocketService;

    @Value("${gpsToAddressUrl}")
    private String gpsToAddressUrl;

    /**
     * 学生校徽报警处理 - 启动校徽报警流程
     * @param data
     */
    @Override
    public Result sosAlarm(String data) {
        Result result = new Result();
        Map<String, Object> studentMap = JSONObject.parseObject(data, Map.class);
        Map<String,Object> stuInfoMap=(Map)studentMap.get("Student");

        //判断有无Gps地址化
        Map<String, Object> gps = (Map<String, Object>) (((List) studentMap.get("Gps")).get(0));
        if (EmptyChecker.isEmpty(gps.get("Address"))) {
            String gpsUrl = gpsToAddressUrl + "&extensions_poi=0&location=" + gps.get("Latitude") + "," + gps.get("Longitude");
            try {
                String addressStr = restTemplate.getForObject(gpsUrl, String.class);
                Map<String, Object> addressMap = JSONObject.parseObject(addressStr, Map.class);
                gps.put("Address", (((Map) (addressMap.get("result"))).get("formatted_address")).toString().split(";")[0]);
            } catch (RestClientException e) {
                gps.put("Address", "");
            }
        }

        try {
            //組裝班級
            String studentExtByStudentIdCardNo = schoolServiceFeign.getStudentExtByStudentIdCardNo(stuInfoMap.get("idCardNo")+"");
            Map<String,Object> stuExtMap= JSONObject.parseObject(studentExtByStudentIdCardNo,Map.class);
            stuInfoMap.put("className",((Map)stuExtMap.get("data")).get("className"));
            stuInfoMap.put("schoolName",((Map)stuExtMap.get("data")).get("schoolName"));
        } catch (Exception e) {
            log.error("查询学生班级等扩展信息处理失败",e);
        }

        //组装推送报警信息->熊涛涛
        AlarmMessageInfo alarmMessageInfo = new AlarmMessageInfo();
        Map<String, Object> extData = new HashMap<>();
        extData.put("student", JSONObject.toJSONString(studentMap));
        alarmMessageInfo.setMessageType(8);
        alarmMessageInfo.setExtData(JSONObject.toJSONString(extData));
        Result re = websocketService.receiveMessageInfo(JSONObject.toJSONString(alarmMessageInfo));
        result.setStatusCode(ResultCodeMsg.CODE_200);
        return result;
    }

    @Override
    public void handleAlarm(String msg) {
        JsonNode jsonNode = JackSonUtils.transJsonNode(msg);
        int type = jsonNode.get("type").asInt();
        //火灾报警柱
        handleDeviceAlarm(jsonNode);
    }


    /**
     * 处理硬件设备报警
     *
     * @param msgJsonNode 消息对象
     */
    private void handleDeviceAlarm(JsonNode msgJsonNode) {
        // 查询设备信息
        JsonNode data = JackSonUtils.transJsonNode(msgJsonNode.get("data").toString());
        String deviceNumber = data.get("deviceNumber").asText();
        String s = schoolServiceFeign.queryByDeviceNumber(deviceNumber);
        JsonNode resultSuccessData = JackSonUtils.getResultSuccessData(s);
        if (null != resultSuccessData) {
            int orgId = resultSuccessData.get("siOrgCode").asInt();
            String s1 = schoolServiceFeign.queryCriAndOrgByOrgCode(String.valueOf(orgId), 0);
            JsonNode resultSuccessData1 = JackSonUtils.getResultSuccessData(s1);

            if (null == resultSuccessData1) {
                log.info("无法查询到组织信息：组织id为{}", orgId);
                return;
            }

            StringBuilder logInfo = new StringBuilder();
            List<Integer> orgAllCodes = new ArrayList<>();
            ArrayNode orgs = JackSonUtils.transArrayNode(JackSonUtils.beanToString(resultSuccessData1.get("orgs")));
            ArrayNode cris = JackSonUtils.transArrayNode(JackSonUtils.beanToString(resultSuccessData1.get("cris")));
            for(JsonNode jsonNode : cris){
                logInfo.append(jsonNode.get("criName").asText());
                logInfo.append(" ");
            }

            for(int i=0; i<orgs.size(); i++){
                orgAllCodes.add(orgs.get(i).get("orgCode").asInt());
                if(i == orgs.size()-1){
                    logInfo.append(orgs.get(i).get("name").asText());
                }
            }
            String type = AlarmType.geteName(msgJsonNode.get("type").asInt());
            String processDefinitionId = commonService.getOrgProcessDefinitionId(orgId, type);
            if (null == processDefinitionId) {
                log.error("流程类型不存在，或者流程已经被挂起：orgCode：{}, type:{}", orgId, type);
                return;
            }

            Map<String, Object> variables = new HashMap<>();
            variables.put("alarmData", JackSonUtils.beanToString(resultSuccessData));
            variables.put("orgCode", orgId);
            variables.put("alarmType", msgJsonNode.get("type").asInt());
            variables.put("createTime", DateUtils.fmtDateForBetRecods(new Date()));
            //所有的组织，
            variables.put("orgAllCodes",JackSonUtils.beanToString(orgAllCodes));
            variables.put("orgInfo",logInfo);
            variables.put("begin_start_description", "【" + resultSuccessData.get("name").asText() + "】触发" + AlarmType.getcName(msgJsonNode.get("type").asInt()));

            //如果是非法出入报警，则需要添加学生信息
            if(msgJsonNode.get("type").asInt() == AlarmType.MJ_ILLEGAL_ACCESS.getKey()){
                JsonNode jsonNode = data.get("info");
                String userCardNo = jsonNode.get("userCardNo").asText();
                String url = jsonNode.get("image").asText();
                String studentExtByStudentIdCardNo = schoolServiceFeign.getStudentExtByStudentIdCardNo(userCardNo);
                JsonNode resultSuccessData2 = JackSonUtils.getResultSuccessData(studentExtByStudentIdCardNo);
                if(null == resultSuccessData2){
                    log.error("学生不存在编号{}不存在，无法启动流程报警 ",userCardNo);
                    return;
                }
                Map<String,Object> map = new HashMap<>(5);
                map.put("studentName",resultSuccessData2.get("studentName").asText());
                map.put("studentSex",resultSuccessData2.get("studentSex").asText());
                map.put("headImage",resultSuccessData2.get("headImage").asText());
                map.put("className",resultSuccessData2.get("className").asText());
                map.put("schoolName",resultSuccessData2.get("schoolName").asText());
                variables.put("studentInfo",JackSonUtils.beanToString(map));
                variables.put(type+"_image",url);
            }

            if(
                    msgJsonNode.get("type").asInt() == AlarmType.IRRELEVANT_PERSONNEL_WANDERING.getKey() || msgJsonNode.get("type").asInt() == AlarmType.BLACKLIST.getKey()
            ){
                JsonNode jsonNode = data.get("info");
                variables.put(type+"_grade",jsonNode.get("grade").asText());
                variables.put(type+ "_snapImage",jsonNode.get("snapImage").asText());
                variables.put(type+ "_comparisonImage",jsonNode.get("comparisonImage").asText());
            }

            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables);
            log.info("启动流程成功：流程类型为：{}, 流程实例ID: {}", type, processInstance.getId());
        } else {
            log.error("查询设备出错！设备不存在或者网络延迟， 设备deviceNumber:  {}", deviceNumber);
        }
    }



    /**
     * 组织人员查询自己的候选任务
     *
     * @param currentLoginUser 当前登录用户
     * @return 结果
     */
    @Override
    public Map<String, Object> candidateTask(CurrentLoginUser currentLoginUser, Integer pageNum, Integer size) {
        String userPhone = currentLoginUser.getPhone() + "";
        //组装候选人任务
        List<Task> candidateTaskList = taskService.createTaskQuery()
                .taskCandidateUser(userPhone)
                .orderByTaskCreateTime()
                .desc()
                .listPage((pageNum - 1) * size, size);
        List<Map<String, Object>> reList = activitiUtilService.taskListBuild(candidateTaskList);
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("list", reList);
        resMap.put("total", taskService.createTaskQuery().taskCandidateUser(userPhone).count());
        return resMap;
    }

    @Override
    public void securityArrival(String json) {

    }

    @Override
    public void claimTask(String taskId, CurrentLoginUser currentLoginUser) {
        taskService.claim(taskId, currentLoginUser.getPhone() + "");
    }

    @Override
    public Result completeTask(CurrentLoginUser currentLoginUser, CompleteTaskPo completeTaskPo) {
        //这名保安队长本身的信息
        String secuId = currentLoginUser.getPhone() + "";

        switch (completeTaskPo.getType()) {
            case "result":
                return this.upInfoSuccess(currentLoginUser, completeTaskPo);
            case "leaderAssign":
                return this.leaderAssign(currentLoginUser, completeTaskPo);
            default:
                log.error("类型错误");
        }
        return null;
    }

    private Result upInfoSuccess(CurrentLoginUser currentLoginUser, CompleteTaskPo completeTaskPo) {
        Result result = new Result();
        String completeName = completeTaskPo.getCompleteName();
        Long completePhone = currentLoginUser.getPhone();
        //任务信息
        String taskId = completeTaskPo.getTaskId();
        Task task = selectTaskByTaskIdAndPhone(taskId, String.valueOf(completePhone));
        if (EmptyChecker.isEmpty(task)) {
            result.setStatusCode(ResultCodeMsg.CODE_501);
            result.setMessage("任务不存在，或者您不是任务候选人");
            return result;
        }
        Map map = JackSonUtils.strToBean(completeTaskPo.getJson(), Map.class);
        map.put("time", DateUtils.formatDateForStandard(new Date()));
        int next = (int) map.get("next");
        //将此保安设置为任务完成人并完成此任务
        Map<String, Object> variables = new HashMap<>(3);
        log.info("==== 用户{}完成节点{} =====", completePhone, task.getTaskDefinitionKey());
        String nodekey = task.getTaskDefinitionKey();
        variables.put(nodekey + "_description_" + taskId, "【" + completeName + "-" + completePhone + "】上报处理结果");
        variables.put(nodekey + "_next", next);
        variables.put(nodekey + "_results_"+ taskId, JackSonUtils.beanToString(map));

        // 判断是不是就是选择角色发送
        if(null !=map.get("nextRoles")){
            variables.put(nodekey+"_roles", map.get("nextRoles"));
        }

        //存报警细节信息/存redis方便保安实施比对位置
        handelCompleteTask(task, taskId, variables, result, completePhone);
        return result;
    }

    @Override
    public Result closeTask(CurrentLoginUser currentLoginUser, CloseTaskPo closeTaskPo) {
        log.info("=====关闭报警=======");
        Result result = new Result();
        String phone = String.valueOf(currentLoginUser.getPhone());
        String taskId = closeTaskPo.getTaskId();
        Task task = selectTaskByTaskIdAndPhone(taskId, phone);
        if (EmptyChecker.isEmpty(task)) {
            result.setStatusCode(ResultCodeMsg.CODE_501);
            result.setMessage("任务不存在，或者您不是任务候选人");
            return result;
        }
        Map map = JackSonUtils.strToBean(closeTaskPo.getJson(), Map.class);
        map.put("time", DateUtils.formatDateForStandard(new Date()));
        Map<String, Object> variables = new HashMap<>();
        String nodeKey = task.getTaskDefinitionKey();
        variables.put(nodeKey + "_description_" + taskId, "【" + closeTaskPo.getCompleteName() + "-" + phone + "】关闭报警");
        variables.put(nodeKey + "_results_" + taskId, JackSonUtils.beanToString(map));
        variables.put(nodeKey + "_next", 0);
        variables.put(nodeKey + "_assign", currentLoginUser.getPhone());
        log.info("=====关闭报警=======");
        log.info(JackSonUtils.beanToString(variables));
        handelCompleteTask(task, taskId, variables, result, currentLoginUser.getPhone());
        return result;
    }


    private Task selectTaskByTaskIdAndPhone(String taskId, String phone) {
        return taskService
                .createTaskQuery()
                .taskId(taskId)
                .singleResult();
    }

    private Result leaderAssign(CurrentLoginUser currentLoginUser, CompleteTaskPo completeTaskPo) {
        Result result = new Result();
        String completeName = completeTaskPo.getCompleteName();
        Long completePhone = currentLoginUser.getPhone();
        Map map = JackSonUtils.strToBean(completeTaskPo.getJson(), Map.class);
        //被分配人信息
        String assignPhone = map.get("assignPhone") + "";
        String assignUser = map.get("assignName") + "";
        //任务信息
        String taskId = completeTaskPo.getTaskId();
        Task task = selectTaskByTaskIdAndPhone(taskId, String.valueOf(completePhone));
        if (EmptyChecker.isEmpty(task)) {
            result.setStatusCode(ResultCodeMsg.CODE_501);
            result.setMessage("任务不存在，或者您不是任务候选人");
            return result;
        }
        //将此保安设置为任务完成人并完成此任务
        Map<String, Object> variables = new HashMap<>();
        log.info("==== 用户{}完成节点{} =====", completePhone, task.getTaskDefinitionKey());
        String nodekey = task.getTaskDefinitionKey();
        variables.put(nodekey + "_assign", assignPhone);
        variables.put(nodekey + "_description_" + taskId, "【" + completeName + "-" + completePhone + "】指派【" + assignUser + "-" + assignPhone + "】处理");
        variables.put(nodekey + "_next", 1);
        //variables.put(nodekey+"_results",map);
        log.info(JackSonUtils.beanToString(variables));
        //存报警细节信息/存redis方便保安实施比对位置
        handelCompleteTask(task, taskId, variables, result, completePhone);
        return result;
    }




    /**
     * 签收完成处理
     *
     * @param task          任务
     * @param taskId        任务id
     * @param variables     变量
     * @param result        结果对象
     * @param completePhone 完成者手机号码
     */
    private void handelCompleteTask(Task task, String taskId, Map<String, Object> variables, Result result, Long completePhone) {
        // 没有候选人，签收任务
        result.setMessage("分配任务成功");
        String assign = task.getAssignee();
        if (StringUtils.isEmpty(assign)) {
            taskService.claim(taskId, String.valueOf(completePhone));
            taskService.complete(taskId, variables);
        } else if (assign.equals(String.valueOf(completePhone))) {
            taskService.complete(taskId, variables);
        } else {
            result.setStatusCode(ResultCodeMsg.CODE_501);
            result.setMessage("不是您的任务，您无权操作！");
        }
    }


    @Override
    public Map<String, Object> assignTask(CurrentLoginUser currentLoginUser, Integer pageNum, Integer size) {
        String secuId = currentLoginUser.getPhone() + "";

        //组装代理人任务
        List<Task> taskList = taskService.createTaskQuery()
                .taskAssignee(secuId)
                .orderByTaskCreateTime()
                .desc()
                .listPage((pageNum - 1) * size, size);
        List<Map<String, Object>> reAssList = activitiUtilService.taskListBuild(taskList);
        Map<String, Object> resMap = new HashMap<>(2);
        resMap.put("list", reAssList);
        resMap.put("total", taskService.createTaskQuery().taskAssignee(secuId).count());
        return resMap;
    }


    @Override
    public Map<String, Object> doneTaskList(CurrentLoginUser currentLoginUser, Integer pageNum, Integer size) {
        Map<String, Object> resMap = new HashMap<>();
        String assignee = currentLoginUser.getPhone() + "";
        //查已办任务
        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(assignee)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .listPage((pageNum - 1) * size, size);
        Long count = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(assignee)
                .finished()
                .count();
        if (EmptyChecker.isEmpty(taskList)) {
            resMap.put("total", count);
            resMap.put("list", taskList);

            return resMap;
        }

        List<Map<String, Object>> res = activitiUtilService.historyTaskListBuild(taskList);
        resMap.put("total", count);
        resMap.put("list", res);
        return resMap;
    }


    @Override
    public Map<String, Object> selectTaskCount(CurrentLoginUser currentLoginUser) {
        Map<String, Object> res = new HashMap<>();
        res.put("assignTask", taskService.createTaskQuery().taskAssignee(currentLoginUser.getPhone() + "").count());
        res.put("candidateTask", taskService.createTaskQuery().taskCandidateUser(currentLoginUser.getPhone() + "").count());
        return res;
    }
}
